#include "baseboardInfo.h"
#include <iostream>
#include <cstring>

BaseboardInfo::~BaseboardInfo()
{
    if (_coHandles != nullptr) {
        delete[] _coHandles;
        _coHandles = nullptr;
    }
}
void 
BaseboardInfo::setGeneral(UINT8 len, const std::string &manufacturer, const std::string &product,
                          const std::string &version, const std::string &serialNumber)
{
    _length = len;
    _manufacturer = manufacturer;
    _product = product;
    _version = version;
    _serialNumber = serialNumber;
}

void 
BaseboardInfo::setCoHandles(UINT8 num, const UINT8 *handle)
{
    _numberOfCoHandles = num;
    if (num > 0) {
        _coHandles = new UINT16[num];
        for (int i = 0; i < num; i++) {
            _coHandles[i] = WORD(handle + sizeof(UINT16) * i);
        }
    }
}

void 
BaseboardInfo::print()
{
    if (_length < 0x08)
        return;
    std::cout << "Base Board Information:" << std::endl;
    std::cout << "\tManufacturer: " << _manufacturer << std::endl;
    std::cout << "\tProduct Name: " << _product << std::endl;
    std::cout << "\tVersion: " << _version << std::endl;
    std::cout << "\tSerial Number: " << _serialNumber << std::endl;
    
    if (_length < 0x09)
        return;
    std::cout << "\tAsset Tag: " << _assetTag << std::endl;

    if (_length < 0x0A)
        return;
    printFeatures();

    if (_length < 0x0E)
        return;
    std::cout << "\tLocation In Chassis: " << _locationInChassis << std::endl;
    printf("\tChassis Handle: 0x%04X\n", _chassisHandle);
    std::cout << "\tBoard Type: " << printBaseBoardType() << std::endl;
}

void 
BaseboardInfo::printBaseBoardHandles()
{
    printf("\tContained Object Handles(%u): ", _numberOfCoHandles);
    for (UINT8 i = 0; i < _numberOfCoHandles; i++)
        printf("0x%04X", _coHandles[i]);
    std::cout << std::endl;
}

const char* 
BaseboardInfo::printBaseBoardType()
{
	/* 7.3.2 */
	static const char *type[] = {
		"Unknown", /* 0x01 */
		"Other",
		"Server Blade",
		"Connectivity Switch",
		"System Management Module",
		"Processor Module",
		"I/O Module",
		"Memory Module",
		"Daughter Board",
		"Motherboard",
		"Processor+Memory Module",
		"Processor+I/O Module",
		"Interconnect Board" /* 0x0D */
	};

	if (_boardType >= 0x01 && _boardType <= 0x0D)
		return type[_boardType - 0x01];
	return OUT_OF_SPEC;
}

void 
BaseboardInfo::printFeatures()
{
	/* 7.3.1 */
	static const char *features[] = {
		"Board is a hosting board", /* 0 */
		"Board requires at least one daughter board",
		"Board is removable",
		"Board is replaceable",
		"Board is hot swappable" /* 4 */
	};

    std::cout << "\tFeatures: ";

    if ((_featureFlags & 0x1F) == 0)
        std::cout << "None" << std::endl;
    else {
		for (int i = 0; i <= 4; i++) {
            std::cout << std::endl;
			if (_featureFlags & (1 << i))
				printf("\t\t%s", features[i]);
        }
	}
    std::cout << std::endl;
}
